﻿#ifndef INSTOBJ_H
#define INSTOBJ_H

#include "attrobj.h"


namespace xvs {



class TaskObj;
class InstObjData;

/**
 * @brief The InstObj class     指令对象类(所有指令的基类)
 * @property    EditorType 编辑器类型
 * @property    ItemType
 */
class OBJLIB_EXPORT InstObj : public XVObject , public IExecuteable
{
    Q_OBJECT
public:
    InstObj();
    virtual ~InstObj();

//    void cloneInstObj(InstObj *copyObj);//对实例的属性对象进行拷贝
//    InstObj* copy();

    virtual QJsonObject Save(const QString& path) override;
    virtual void Load(QJsonObject &json,const QString& path) override;

public:
    /**
     *  为指令对象添加输入属性
     */
    template <typename T>
    AttrObj* AddInAttrObj(const QString& name,T& data,EnumVisibleType visible = VisibleType_False)
    {
        AttrObj* obj = AddAttrObj(name);
        obj->SetVisible(visible);

        QVariant tempD = QVariant::fromValue<T*>(&data);
        if (!tempD.canConvert<BaseData*>())
            THROW_ERROR(DomainError,tr("Wrong data type, data must be based on BaseData*"));

        obj->SetData(QVariant::fromValue<T*>(&data));

        //obj->SetDefaultData(QVariant::fromValue<T*>(&data));
        return obj;
    }

    /**
     *  为指令对象添加输出属性
     */
    template <typename T>
    AttrObj* AddOutAttrObj(const QString& name,T& data,EnumVisibleType visible = VisibleType_False)
    {
        AttrObj* obj = AddAttrObj(name,AttrType_Out);
        obj->SetVisible(visible);

        QVariant tempD = QVariant::fromValue<T*>(&data);
        if (!tempD.canConvert<BaseData*>())
            THROW_ERROR(DomainError,tr("Wrong data type, data must be based on BaseData*"));

        obj->SetData(tempD);

        return obj;
    }

    /**
     * @brief 移除该指令对象中的属性(属性对象会被销毁)
     * @param name 要移除的属性名称
     * @param isInput 输入属性 = true;  输出对象 = false
     * @relates (AttrObj*)obj->deleteLater();
     */
    void RemoveInAttrObj(const QString& name, EnumAttrType type = AttrType_In);

    /**
     *  获取指令中输入属性的值
     */
    template <typename T>
    void ReadInAttrObj(const QString& name,T& outData)
    {
        ReadInAttrObj(AttrObjByDesc(name),outData);
    }
    /**
     *  更新指令中输入属性的值
     */
    template <typename T>
    void WriteInAttrObj(const QString& name, T& inData)
    {
        WriteInAttrObj(AttrObjByDesc(name,AttrType_In),inData);
    }

    /**
     *  获取指令中输出属性的值
     */
    template <typename T>
    void ReadOutAttrObj(const QString& name,T& outData)
    {
        ReadOutAttrObj(AttrObjByDesc(name),outData);
    }
    /**
     *  更新指令中输出属性的值
     */
    template <typename T>
    void WriteOutAttrObj(const QString& name, T& inData)
    {
        WriteOutAttrObj(AttrObjByDesc(name,AttrType_Out),inData);
    }

public:
    /**
     *  获取指令中输入属性的值
     */
    template <typename T>
    void ReadInAttrObj(AttrObj* obj,T& outData)
    {
        if (nullptr == obj)
            THROW_ERROR(DomainError,tr("attrobj is nullptr"));

        outData = *obj->Data().value<T*>();
    }
    /**
     *  更新指令中输入属性的值
     */
    template <typename T>
    void WriteInAttrObj(AttrObj* obj, T& inData)
    {
        if (obj == nullptr)
            THROW_ERROR(DomainError,tr("attrobj is nullptr"));

        obj->SetData(QVariant::fromValue<T*>(&inData));
    }

    /**
     *  获取指令中输出属性的值
     */
    template <typename T>
    void ReadOutAttrObj(AttrObj* obj,T& outData)
    {
        if (nullptr == obj)
            THROW_ERROR(DomainError,tr("attrobj is nullptr"));
        outData = *obj->Data().value<T*>();
    }
    /**
     *  更新指令中输出属性的值
     */
    template <typename T>
    void WriteOutAttrObj(AttrObj* obj, T& inData)
    {
        if (obj == nullptr)
            THROW_ERROR(DomainError,tr("attrobj is nullptr"));

        obj->SetData(QVariant::fromValue<T*>(&inData));
    }

    /**
     * @brief 添加指令对象的属性(新创建的属性对象没有数据)
     * @param name  要添加的属性名称
     * @param isInput 输入属性 = true;  输出对象 = false
     * @return  返回添加的属性对象
     */
    AttrObj* AddAttrObj(const QString& name, EnumAttrType type = AttrType_In);

    AttrObj* AttrObjByDesc(const QString& desc, EnumAttrType type = AttrType_In);

    AttrObj* AttrObjByCode(const QString& code,EnumAttrType type = AttrType_In);

    /**
     * @brief Links 当前指令对象包含的所有链接属性对象
     * @return
     */
    QList<AttrObj*> Links();

public://自身属性
    /**
     * @brief RootObj   获取指令对象输入(出)根属性
     * @param type      输入/输出
     */
    AttrObj* AttrObjRoot(EnumAttrType type = AttrType_In);

    EnumInstType InstType() const;
    void SetInstType(const EnumInstType type);

    QString ItemType() const;//数组:内部项
    void SetItemType(const QString& type);

signals:
    void signal_attrDataChanged(AttrObj*);

private:
    InstObjData* d_ptr;
};




}

#endif // INSTOBJ_H
